home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Periodicals / develop / develop 4 code / A⁄ROSE / MCPMBƒ / Exercise.c next >
Encoding:
C/C++ Source or Header  |  1990-08-28  |  27.8 KB  |  1,142 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    Exercise.c
  4. #
  5. #    derived from MPW 3.1's "Sample", a MultiFinder-Aware Simple Sample Application
  6. #
  7. #   Demonstrates how to use A/ROSE tasks for parallel processing 
  8. #    (one more program which computes Mandelbrot sets ...)
  9. #   
  10. #   One resizeable window; allows to select zoom-in rectangle
  11. #   (was meant to be an introductory Macintosh C-programming exercise, originally)
  12. #
  13. #   Refer to the original source code in the MPW CExamples folder for more comments
  14. #
  15. #    Components:
  16. #                Exercise.c
  17. #                Exercise.r
  18. #                Exercise.h
  19. #                Exercise.make
  20. #
  21. ------------------------------------------------------------------------------*/
  22. /* -------------- MPW: select the following lines + <ENTER> ------
  23. Asm iter16.a
  24. C Exercise.c -r
  25. Link -o Exercise ∂
  26.       Exercise.c.o iter16.a.o ∂
  27.         ::IPCGlue.o ∂
  28.       "{CLibraries}"CRuntime.o ∂
  29.       "{CLibraries}"CInterface.o ∂
  30.       "{Libraries}"Interface.o ∂
  31.       "{CLibraries}"CSANElib.o 
  32. Rez Exercise.r -o Exercise -a
  33. Exercise
  34. ---------------------------------------------------------------- */
  35.  
  36. #include <Types.h>
  37. #include <QuickDraw.h>
  38. #include <Fonts.h>
  39. #include <Events.h>
  40. #include <Controls.h>
  41. #include <Windows.h>
  42. #include <Menus.h>
  43. #include <Dialogs.h>
  44. #include <Desk.h>
  45. #include <ToolUtils.h>
  46. #include <Memory.h>
  47. #include <SegLoad.h>
  48. #include <Packages.h>
  49. #include <DiskInit.h>
  50. #include <OSEvents.h>
  51. #include <OSUtils.h>
  52. #include <Traps.h>
  53. #include <SANE.h>
  54. #include <Strings.h>
  55.  
  56. #include "Exercise.h"    // bring in all the #defines for Exercise
  57.  
  58. //---------------------------------------------------------------------------
  59. // A/ROSE declarations (from "os.h"):
  60.  
  61. typedef long    tid_type;
  62.  
  63. struct mMessage
  64. {
  65.     struct    mMessage    *mNext;
  66.     long                mId;
  67.     short                mCode;
  68.     short                mStatus;
  69.     unsigned    short    mPriority;
  70.     tid_type            mFrom;
  71.     tid_type            mTo;
  72.     unsigned    long    mSData [3];
  73.     unsigned    long    mOData [3];
  74.     long                mDataSize;        // Size of data buffer in bytes. set to negative 
  75.                                         // size of buffer if buffer is shared
  76.                                         // between tasks. eg. Buffer cannot be copied 
  77.     char                *mDataPtr;
  78. };
  79.  
  80. typedef struct mMessage mMessage;
  81.  
  82. #define    OS_MATCH_ALL    0        // on receive match anything
  83. #define    OS_NO_TIMEOUT    0        // receive waits forever for message
  84.  
  85. // and some #define's from "managers.h":
  86.  
  87. #define    OS_UNKNOWN_MESSAGE        (1<<8)    // unknown message                    
  88. #define    Machine_Visible            0        // Register_task Machine visible flag    
  89.  
  90. #define    ICC_GETCARDS    150        // Get list of active cards and their name mgr TID
  91.  
  92. //---------------------------------------------------------------------------
  93.  
  94. // prototypes
  95.  
  96. void Initialize(void);
  97. Boolean TrapAvailable(short tNumber, TrapType tType);
  98. void AlertUser(short error);
  99. void BigBadError(short error);
  100. Boolean DoCloseWindow(WindowPtr window);
  101. Boolean IsAppWindow(WindowPtr window);
  102. Boolean IsDAWindow(WindowPtr window);
  103. void Terminate();
  104.  
  105. void DoMouseDown(EventRecord *theEvent);        
  106. void DoContentClick(WindowPtr window, EventRecord *event);
  107. void EventLoop(void);        
  108. void DoEvent(EventRecord *event);
  109. void DoUpdate(WindowPtr window);
  110. void DoActivate(WindowPtr window, Boolean becomingActive);
  111. void DrawWindow(WindowPtr window);        
  112. void ShowCount(Boolean CPU);
  113. void AdjustMenus();
  114. void enable(MenuHandle menu, short item, Boolean okok);        
  115. void DoMenuCommand(long mSelect);        
  116. void InitNewRun();
  117. void ResetSlotServers();
  118. short NextLine(Ptr st, char **linePtr);
  119. void DoCPUcomputation(void);
  120. void UpdateBitmap(short y, Boolean CPU);
  121. void Mandelbrot(void);
  122. Boolean MakeOffScreen();
  123. void CreateMyWindow(void);
  124. void DoGrowWindow(WindowPtr window, EventRecord *event);
  125. short AROSEPrep(tid_type *t);
  126. Boolean     AskICCM(char *Cards);
  127. short FindAllServers(char *name, char *type);
  128. void GetnewSelection(void);
  129. void StringCopy(char *s, char *t);
  130. extern pascal short ITER16(short cx, short cy, short gNmax);
  131.  
  132. // A/ROSE prototypes: --------------------
  133.  
  134. extern    mMessage    *GetMsg(void);
  135. extern    void        FreeMsg();
  136. extern    mMessage    *Receive();
  137. extern    void        Send(mMessage *);
  138.  
  139. extern    tid_type    GetTID(void);
  140. extern    tid_type    GetICCTID(void);
  141. extern    char         Register_Task();
  142. extern    tid_type    Lookup_Task(char *, char *, tid_type, unsigned short *);
  143. extern    unsigned short    GetTickPS();
  144.  
  145. extern    tid_type    OpenQueue();
  146. extern    void        CloseQueue();
  147. //----------------------------------------
  148.  
  149. // Define HiWrd and LoWrd macros for efficiency. 
  150. #define HiWrd(aLong)    (((aLong) >> 16) & 0xFFFF)
  151. #define LoWrd(aLong)    ((aLong) & 0xFFFF)
  152.  
  153.  
  154. // global variables 
  155.  
  156. SysEnvRec    gMac;                        // set up by Initialize 
  157. Boolean        gHasWaitNextEvent;    // set up by Initialize 
  158. Boolean        gInBackground;            // maintained by Initialize and DoEvent 
  159. WindowPtr     gMyWindow;
  160. tid_type        gTID;                        // my task identifier returned by OpenQueue()
  161.                                             // = 0 if A/ROSE not available
  162.  
  163. Rect            gRect;                    // to display Mandelbrot set in gMyWindow
  164. ControlHandle gCPUctlH,
  165.                 gMCPctlH;                // checkboxes to activate parallel computation
  166.  
  167. Boolean        gDone;
  168.                 gCPU = false;
  169.                 gMCP = false;
  170.                 gMCPpending[16];        // waiting for an A/ROSE message from a slot ?
  171.  
  172. tid_type        gServerTID[16];        // TID's of MBServers in NuBus slots
  173.             
  174. BitMap        gOffScreen;
  175.  
  176. enum     {empty, busy, full};        // track state of each line to compute
  177. typedef unsigned char state;
  178. state    gLineState[kMaxHeight];
  179.  
  180.  
  181. struct MBvariables {                // used in Mandelbrot(), InitNewRun() and ShowCount()
  182.     short        nmax;                    // max. depth of iteration
  183.     short        d;                        // corresponding to coord. distance between pixels
  184.     short        cx, cy;                // current point of the complex plane to be computed
  185.                                         // these first eight bytes are parameters for the MBTask !
  186.     short        yMCP;
  187.     short        ix, iy;                // counters 0..nx-1, 0..ny-1
  188.     short        xa, ya;                // topleft point in the complex plane
  189.                                         
  190.     short        nx, ny;                // size of rectangle
  191.     short        cntCPU, cntMCP;    // number of lines computed
  192.     extended ncenterx,
  193.                 ncentery,
  194.                 nxextent;            // initial default values (coord. in the complex plane)
  195.     extended centerx,
  196.                 centery,
  197.                 xextent;                // coordinates after zooming in
  198. };
  199.  
  200. typedef struct MBvariables MBvariables;
  201.  
  202. MBvariables    gMBvars;
  203.  
  204. extern void _DataInit();
  205.  
  206. //===============================
  207. main()
  208. //===============================
  209. {
  210.     UnloadSeg((Ptr) _DataInit);        // note that _DataInit must not be in Main! 
  211.     
  212.     MaxApplZone();                    // expand the heap so code segments load at the top 
  213.  
  214.     Initialize();                    // initialize the program 
  215.     UnloadSeg((Ptr) Initialize);    // note that Initialize must not be in Main! 
  216.  
  217.     EventLoop();                    // call the main event loop 
  218.  
  219. }
  220.  
  221.  
  222. #pragma segment Initialize
  223. //===============================
  224. void Initialize(void)
  225. //===============================
  226. {
  227.     Handle        menuBar;
  228.     long            total, contig;
  229.     EventRecord event;
  230.     short            count, result;
  231.     Ptr            windowP;
  232.  
  233.     InitGraf((Ptr) &qd.thePort);
  234.     InitFonts();
  235.     InitWindows();
  236.     InitMenus();
  237.     TEInit();
  238.     InitDialogs(nil);
  239.     InitCursor();
  240.  
  241.     gInBackground = false;
  242.     
  243.     //    This next bit of code is necessary to allow the default button of our
  244.     //    alert be outlined. 
  245.      
  246.     for (count = 1; count <= 3; count++)
  247.         EventAvail(everyEvent, &event);
  248.     
  249.     SysEnvirons(kSysEnvironsVersion, &gMac);
  250.     
  251.     if (gMac.machineType < 0)
  252.         BigBadError(eWrongMachine);
  253.     
  254.     if (! TrapAvailable(_WaitNextEvent, ToolTrap))
  255.         BigBadError(eWrongMachine);
  256.  
  257.     if ((long) GetApplLimit() - (long) ApplicZone() < kMinHeap)
  258.         BigBadError(eSmallSize);
  259.     
  260.     // ZeroScrap(); 
  261.  
  262.     PurgeSpace(&total, &contig);
  263.     if (total < kMinSpace)
  264.         BigBadError(eNoMemory);
  265.  
  266.     gTID = 0;            // in case A/ROSE will not be available
  267.     result = AROSEPrep(&gTID);    // side effect: returns gServerTID[0..15] !
  268.     if (result != noErr) {
  269.         if (gTID > 0)    {        // if we registered with .IPC --
  270.             CloseQueue();         // better clean up
  271.          gTID = 0;
  272.         }
  273.         AlertUser(result);
  274.     }
  275.     for (count = 0; count < 16; count++)
  276.         gMCPpending[count] = false;
  277.  
  278.     windowP = NewPtr(sizeof(WindowRecord)); // we allocate storage ourselves
  279.     if ( windowP == nil )
  280.         BigBadError(eNoWindow);
  281.  
  282.     gMyWindow = GetNewWindow(rWindow, windowP, (WindowPtr) -1);
  283.     if ( gMyWindow == nil )
  284.         BigBadError(eNoWindow);
  285.  
  286.     gRect =     gMyWindow->portRect;
  287.     InsetRect(&gRect, kBord, kBord);
  288.     gRect.bottom = gRect.bottom - kBottom + kBord;
  289.     
  290.     if (!MakeOffScreen())
  291.         BigBadError(eNoBitMap);
  292.  
  293.     gCPUctlH = GetNewControl(rCPUchk, gMyWindow);    // to activate CPU computation
  294.     gMCPctlH = GetNewControl(rMCPchk, gMyWindow);    // to activate MCP computation
  295.     
  296.     if ((gCPUctlH == nil) | (gMCPctlH == nil))
  297.         BigBadError(eNoWindow);
  298.     MoveControl(gCPUctlH , gRect.left, gRect.bottom + 8);
  299.     MoveControl(gMCPctlH , gRect.left, gRect.bottom + 24);
  300.  
  301.     gMBvars.ncenterx = -0.5;
  302.     gMBvars.ncentery = 0.0;
  303.     gMBvars.nxextent = 3.0;
  304.     
  305.     InitNewRun();            // initializes the other fields of gMBvars, resets MBTasks etc.
  306.         
  307.     menuBar = GetNewMBar(rMenuBar);            // read menus into menu bar 
  308.     if ( menuBar == nil )
  309.         BigBadError(eNoMemory);
  310.     SetMenuBar(menuBar);                    // install menus 
  311.     DisposHandle(menuBar);
  312.     AddResMenu(GetMHandle(mApple), 'DRVR');    // add DA names to Apple menu 
  313.     DrawMenuBar();
  314.  
  315. } //Initialize
  316.  
  317.  
  318. #pragma segment Initialize
  319. //===============================
  320. Boolean TrapAvailable(short tNumber, TrapType tType)
  321. //===============================
  322. {
  323.     if ( ( tType == ToolTrap ) &&
  324.         ( gMac.machineType > envMachUnknown ) &&
  325.         ( gMac.machineType < envMacII ) ) {        // it's a 512KE, Plus, or SE 
  326.         tNumber = tNumber & 0x03FF;
  327.         if ( tNumber > 0x01FF )                    // which means the tool traps 
  328.             tNumber = _Unimplemented;            // only go to 0x01FF 
  329.     }
  330.     return NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented);
  331. } //TrapAvailable
  332.  
  333.  
  334. #pragma segment Main
  335. //===============================
  336. void Terminate()
  337. //===============================
  338. {
  339.     WindowPtr    aWindow;
  340.     Boolean        closed;
  341.     
  342.     if (gTID > 0) {
  343.         ResetSlotServers();
  344.         CloseQueue();                // Clean up interaction with A/ROSE Prep
  345.     }
  346.  
  347.     if (gOffScreen.baseAddr != nil)
  348.         DisposPtr(gOffScreen.baseAddr);
  349.         
  350.     closed = true;
  351.     do {
  352.         aWindow = FrontWindow();                // get the current front window
  353.         if (aWindow != nil)
  354.             closed = DoCloseWindow(aWindow);    //  close this window    
  355.     }
  356.     while (closed && (aWindow != nil));
  357.     if (closed)
  358.         ExitToShell();                            // exit if no cancellation
  359. } // Terminate
  360.  
  361.  
  362. #pragma segment Main
  363. //===============================
  364. Boolean DoCloseWindow(WindowPtr window)
  365. //===============================
  366. {
  367.     if ( IsDAWindow(window) )
  368.         CloseDeskAcc(((WindowPeek) window)->windowKind);
  369.     else if ( IsAppWindow(window) )
  370.         CloseWindow(window);
  371.     return true;
  372. } //DoCloseWindow
  373.  
  374.  
  375. #pragma segment Main
  376. //===============================
  377. Boolean IsAppWindow(WindowPtr window)
  378. //===============================
  379. {
  380.     short        windowKind;
  381.  
  382.     if ( window == nil )
  383.         return false;
  384.     else {    // application windows have windowKinds = userKind (8) 
  385.         windowKind = ((WindowPeek) window)->windowKind;
  386.         return (windowKind = userKind);
  387.     }
  388. } //IsAppWindow
  389.  
  390.  
  391. #pragma segment Main
  392. //===============================
  393. Boolean IsDAWindow(WindowPtr window)
  394. //===============================
  395. {
  396.     if ( window == nil )
  397.         return false;
  398.     else    // DA windows have negative windowKinds 
  399.         return ((WindowPeek) window)->windowKind < 0;
  400. } //IsDAWindow
  401.  
  402.  
  403. #pragma segment Main
  404. //===============================
  405. void AlertUser( short error)
  406. //===============================
  407. {
  408.     short        itemHit;
  409.     Str255        errMsg;
  410.  
  411.     SetCursor(&qd.arrow);
  412.     if ((error>0)&&(error<=kLastErrStr)) {
  413.         GetIndString(errMsg, rErrStrings, error);
  414.         ParamText(errMsg, "", "", "");
  415.     }
  416.     else {
  417.         NumToString(error, &errMsg);
  418.         ParamText("\pUnknown error", errMsg, "", "");
  419.     }
  420.         
  421.     itemHit = Alert(rUserAlert, nil);
  422. } // AlertUser 
  423.  
  424. #pragma segment Main
  425. //===============================
  426. void BigBadError( short error)
  427. //===============================
  428. {
  429.     AlertUser(error);
  430.     ExitToShell();
  431. }
  432.  
  433. #pragma segment Main
  434. //===============================
  435. void AdjustMenus()
  436. //===============================
  437. {
  438.     WindowPtr    window;
  439.     MenuHandle    menu;
  440.  
  441.     window = FrontWindow();
  442.  
  443.     menu = GetMHandle(mFile);
  444.     
  445.     if ( IsDAWindow(window) )        // we can allow desk accessories to be closed from the menu 
  446.         EnableItem(menu, iClose);
  447.     else
  448.         DisableItem(menu, iClose);    // but not our only window 
  449.     EnableItem(menu, iNew);
  450.     EnableItem(menu, iReset);
  451.     EnableItem(menu, iQuit);
  452.  
  453.     menu = GetMHandle(mEdit);
  454.     if ( IsDAWindow(window) ) {        // a desk accessory might need the edit menu… 
  455.         EnableItem(menu, iUndo);
  456.         EnableItem(menu, iCut);
  457.         EnableItem(menu, iCopy);
  458.         EnableItem(menu, iClear);
  459.         EnableItem(menu, iPaste);
  460.     } else {                        // …but we don’t use it 
  461.         DisableItem(menu, iUndo);
  462.         DisableItem(menu, iCut);
  463.         DisableItem(menu, iCopy);
  464.         DisableItem(menu, iClear);
  465.         DisableItem(menu, iPaste);
  466.     }
  467. } //AdjustMenus
  468.  
  469.  
  470.  
  471. #pragma segment Main
  472. //===============================
  473. void DoMenuCommand (menuResult)
  474. //===============================
  475. long    menuResult;
  476. {
  477.     short        menuID = HiWord(menuResult);
  478.     short        menuItem = LoWord(menuResult);
  479.     short        daRefNum;
  480.     short        itemHit;
  481.     Str255    daName;
  482.     
  483.     switch (menuID)
  484.     {
  485.       case    mApple:
  486.             switch ( menuItem ) {
  487.                 case iAbout:        // bring up alert for About 
  488.                     itemHit = Alert(rAboutAlert, nil);
  489.                     break;
  490.                 default:            // non-About items in this menu are DAs 
  491.                     GetItem(GetMHandle(mApple), menuItem, daName);
  492.                     daRefNum = OpenDeskAcc(daName);
  493.                     break;
  494.             }
  495.             break;
  496.  
  497.       case    mFile:
  498.         switch (menuItem)
  499.           {
  500.           case    iNew:
  501.                         InitNewRun();
  502.                     break;
  503.             
  504.             case    iReset:
  505.                           gMBvars.ncenterx = -0.5;
  506.                         gMBvars.ncentery = 0.0;
  507.                         gMBvars.nxextent = 3.0;
  508.                         InitNewRun();
  509.                       break;
  510.                     
  511.           case    iQuit:
  512.                         Terminate();
  513.                     break;
  514.           }
  515.         break;
  516.                   
  517.       case    mEdit:
  518.         if (!SystemEdit(menuItem-1))
  519.           SysBeep(5);
  520.         break;
  521.         
  522.     }
  523.     HiliteMenu(0);        // unhighlight what MenuSelect (or MenuKey) hilited 
  524. }
  525.  
  526.  
  527. #pragma segment Main
  528. //===============================
  529. void DoContentClick(WindowPtr window, EventRecord *event)
  530. //===============================
  531. {
  532.     Point            mouse;
  533.     ControlHandle    control;
  534.     short    dummy;
  535.     
  536.     if ( IsAppWindow(window) ) {
  537.         SetPort(window);
  538.         mouse = event->where;                            // get the click position 
  539.         GlobalToLocal(&mouse);
  540.         if ( FindControl(mouse, window, &control) == inCheckBox) {
  541.             dummy = TrackControl(control, mouse, nil);
  542.             if (control==gCPUctlH) {
  543.                 gCPU = !gCPU;
  544.                 SetCtlValue(gCPUctlH, (short)gCPU);
  545.             }
  546.             if (control==gMCPctlH) {
  547.                 gMCP = !gMCP;
  548.                 SetCtlValue(gMCPctlH, (short)gMCP);
  549.             }
  550.         }
  551.         else if (PtInRect(mouse, &gRect))
  552.             GetnewSelection();
  553.     }
  554. }
  555.  
  556.  
  557. #pragma segment Main
  558. //===============================
  559. void ShowCount(Boolean CPU)
  560. //===============================
  561. {
  562. Rect rr;
  563. Str255 s;
  564.     
  565.     SetRect(&rr, gRect.left+kCntPos, gRect.bottom+6, gRect.left+kCntPos+30, gRect.bottom+20);
  566.     if (!CPU) OffsetRect(&rr,0,16);
  567.     if (CPU)
  568.         NumToString(gMBvars.cntCPU,s);
  569.     else
  570.         NumToString(gMBvars.cntMCP,s);
  571.     EraseRect(&rr);
  572.     MoveTo(rr.left,rr.bottom);
  573.     DrawString(s);
  574. }
  575.  
  576. #pragma segment Main
  577. //===============================
  578. void DrawWindow(WindowPtr window)
  579. //===============================
  580. {
  581. RgnHandle rh;
  582. Rect cr;
  583. GrafPtr    savePort;
  584.     
  585.     GetPort(&savePort);
  586.     SetPort(window);
  587.     InsetRect(&gRect,-1,-1);
  588.     FrameRect(&gRect);
  589.     InsetRect(&gRect,1,1);
  590.     EraseRect(&gRect);
  591.     CopyBits(&gOffScreen, &(window->portBits), &gRect, &gRect, srcCopy, nil);
  592.  
  593.     if (gTID > 0) 
  594.         HiliteControl(gMCPctlH, 0);        // MCP enabled
  595.     else
  596.         HiliteControl(gMCPctlH, 255);        // MCP disabled
  597.  
  598.     DrawControls(window);
  599.  
  600.     ShowCount(true);
  601.     ShowCount(false);
  602.  
  603.     rh = NewRgn();
  604.     GetClip(rh);
  605.     cr = window->portRect;
  606.     cr.top = cr.bottom - 14;
  607.     cr.left = cr.right - 14;
  608.     ClipRect(&cr);
  609.     DrawGrowIcon(window);
  610.     SetClip(rh);
  611.     SetPort(savePort);
  612. }
  613.  
  614.  
  615. #pragma segment Main
  616. //===============================
  617. void UpdateBitmap(short y, Boolean MCP)
  618. //===============================
  619. {
  620. Rect ir;
  621. GrafPtr savePort;
  622.  
  623.     ir = gRect;
  624.     ir.top = ir.top + y;
  625.     ir.bottom = ir.top + 1;
  626.  
  627.     GetPort(&savePort);
  628.     SetPort(gMyWindow);
  629.     InvalRect(&ir);
  630.     ShowCount(!MCP);
  631.     SetPort(savePort);
  632. }
  633.  
  634.  
  635. #pragma segment Main
  636. //===============================
  637. void Mandelbrot(void)
  638. //===============================
  639. {
  640.     static char    *linestart;
  641.     short     cx, cy, ty;
  642.     short        slot;
  643.     mMessage    *m;
  644.     char        *MCPbuffer;
  645.  
  646.     if (gCPU) {        
  647.         if (gMBvars.iy<0) 
  648.             gMBvars.iy = NextLine(gLineState, &linestart);
  649.         
  650.         if (gMBvars.iy < gMBvars.ny) {
  651.             cx = gMBvars.xa + gMBvars.d*gMBvars.ix;
  652.             cy = gMBvars.ya + gMBvars.d*gMBvars.iy;
  653.             
  654.             if (ITER16(cx, cy, gMBvars.nmax) & 0x1)
  655.                 BitSet(linestart,gMBvars.ix);
  656.             
  657.             gMBvars.ix += 1;
  658.             if (gMBvars.ix == gMBvars.nx) {
  659.                 gLineState[gMBvars.iy] = full;
  660.                 gMBvars.cntCPU += 1;
  661.                 UpdateBitmap(gMBvars.iy, false);
  662.                 gMBvars.iy = NextLine(gLineState, &linestart);
  663.                 gMBvars.ix = 0;
  664.             }
  665.         }
  666.     }
  667.  
  668.     for (slot = 0; slot<16; slot++) {
  669.         if (gMCPpending[slot]) {
  670.              m = Receive(OS_MATCH_ALL, gServerTID[slot], OS_MATCH_ALL, -1L, nil);
  671.             // accept all message IDs,
  672.             // accept messages coming from gServerTID[slot] only
  673.             // accept all message codes
  674.             // -1L: return without waiting
  675.             // nil: no completion routine
  676.             
  677.             if ((long) m > 0) {
  678.                 ty = m->mOData[0];         // line number sent back by server
  679.                 if (m->mStatus == 0)    {
  680.                     gMCPpending[slot] = false;
  681.                     gLineState[ty] = full;
  682.                     gMBvars.cntMCP += 1;
  683.                     UpdateBitmap(ty, true);
  684.                     }
  685.                 else {
  686.                     if (m->mStatus == OS_UNKNOWN_MESSAGE)
  687.                         AlertUser(eUnknownMsg);                
  688.                     else {
  689.                         AlertUser(eUndeliverable);
  690.                         gMCPpending[slot] = false;
  691.                         gLineState[ty] = empty;
  692.                         gServerTID[slot] = 0;     // no server any more in this slot!
  693.                     }
  694.                 }
  695.                 FreeMsg(m);
  696.             }
  697.         }
  698.         if (gMCP && !gDone && !gMCPpending[slot] && (gServerTID[slot]>0)) {
  699.             gMBvars.yMCP = NextLine(gLineState, &MCPbuffer);
  700.             if (gMBvars.yMCP < gMBvars.ny) {
  701.                 m = GetMsg();
  702.                 if ((long)m == 0)
  703.                     DebugStr("\pGetMsg failed");
  704.  
  705. //                m->mFrom         : filled in by GetMsg();
  706.                 m->mTo = gServerTID[slot];
  707.                 m->mCode = MBCODE;
  708.                 gMBvars.cx = gMBvars.xa;
  709.                 gMBvars.cy = gMBvars.ya + gMBvars.d*gMBvars.yMCP;
  710.                 BlockMove((char *)&gMBvars, (char *)&m->mSData[0], 12);        // sender defined data !
  711.                 
  712.                 m->mDataSize = gOffScreen.rowBytes;
  713.                 m->mDataPtr = MCPbuffer;    
  714.                 Send(m);
  715.                 gMCPpending[slot] = true;
  716.             }
  717.             else 
  718.                 gDone = true;
  719.         }
  720.     }
  721. }
  722.  
  723.  
  724. #pragma segment Main
  725. //===============================
  726. void EventLoop()
  727. //===============================
  728. {
  729.     EventRecord    event;
  730.  
  731.     do {
  732.         if (WaitNextEvent(everyEvent, &event, 0L, nil))    // minimum sleep value ...
  733.             DoEvent(&event);
  734.  
  735.         else // idle time !
  736.             Mandelbrot();
  737.         
  738.     } while (true);    // loop forever; we quit via Terminate/ExitToShell 
  739. } //EventLoop
  740.  
  741.  
  742. #pragma segment Main
  743. //===============================
  744. void DoEvent(EventRecord *event)
  745. //===============================
  746. {
  747.     short        part, err;
  748.     WindowPtr    window;
  749.     char        key;
  750.     Point        aPoint;
  751.  
  752.     switch ( event->what ) {
  753.         case mouseDown:
  754.             part = FindWindow(event->where, &window);
  755.             switch ( part ) {
  756.                 case inMenuBar:                // process a mouse menu command (if any) 
  757.                     AdjustMenus();
  758.                     DoMenuCommand(MenuSelect(event->where));
  759.                     break;
  760.                 case inSysWindow:            // let the system handle the mouseDown 
  761.                     SystemClick(event, window);
  762.                     break;
  763.                 case inDrag:                // pass screenBits.bounds to get all gDevices 
  764.                     DragWindow(window, event->where, &qd.screenBits.bounds);
  765.                     break;
  766.                 case inGrow:
  767.                     if (window == gMyWindow)
  768.                         DoGrowWindow(window, event);
  769.                     break;
  770.                 case inContent:
  771.                     if ( window != FrontWindow() ) {
  772.                         SelectWindow(window);
  773.                     } else
  774.                         DoContentClick(window, event);
  775.                     break;
  776.             }
  777.             break;
  778.         case keyDown:
  779.         case autoKey:                        // check for menukey equivalents 
  780.             key = event->message & charCodeMask;
  781.             if ( event->modifiers & cmdKey )            // Command key down 
  782.                 if ( event->what == keyDown ) {
  783.                     AdjustMenus();                        // enable/disable/check menu items properly 
  784.                     DoMenuCommand(MenuKey(key));
  785.                 }
  786.             break;
  787.         case activateEvt:
  788.             DoActivate((WindowPtr) event->message, (event->modifiers & activeFlag) != 0);
  789.             break;
  790.         case updateEvt:
  791.             DoUpdate((WindowPtr) event->message);
  792.             break;        
  793.         case diskEvt:
  794.             if ( HiWord(event->message) != noErr ) {
  795.                 SetPt(&aPoint, kDILeft, kDITop);
  796.                 err = DIBadMount(aPoint, event->message);
  797.                 // so that the user can format a floppy. 
  798.             }
  799.             break;
  800.         case kOSEvent:
  801.             switch ((event->message >> 24) & 0x0FF) {        // high byte of message 
  802.                 case kSuspendResumeMessage:        // suspend/resume is also an activate/deactivate 
  803.                     gInBackground = (event->message & kResumeMask) == 0;
  804.                     DoActivate(FrontWindow(), !gInBackground);
  805.                     break;
  806.             }
  807.             break;
  808.     }
  809. } //DoEvent
  810.  
  811.  
  812. #pragma segment Main
  813. //===============================
  814. void DoUpdate(WindowPtr window)
  815. //===============================
  816. {
  817.     if ( IsAppWindow(window) ) {
  818.         BeginUpdate(window);        // this sets up the visRgn 
  819.                                         // draw if updating needs to be done 
  820.         if ( ! EmptyRgn(window->visRgn) )
  821.             DrawWindow(window);
  822.         EndUpdate(window);
  823.     }
  824. } //DoUpdate
  825.  
  826.  
  827. #pragma segment Main
  828. //===============================
  829. void DoActivate(WindowPtr window, Boolean becomingActive)
  830. //===============================
  831. {
  832.     if ( IsAppWindow(window) ) {
  833.         if ( becomingActive )
  834.             ; // do whatever you need to at activation
  835.         else
  836.             ; // do whatever you need to at deactivation
  837.     }
  838. } //DoActivate
  839.  
  840.  
  841. #pragma segment Main
  842. //===============================
  843. void DoGrowWindow(WindowPtr window, EventRecord *event)
  844. //===============================
  845. {
  846.     long        growResult;
  847.     Rect        tempRect;
  848.     GrafPtr    savePort;
  849.     
  850.     GetPort(&savePort);
  851.     SetPort(gMyWindow);
  852.     tempRect.left = kMinWidth;
  853.     tempRect.top  = kMinHeight;
  854.     tempRect.right = kMaxWidth;                    
  855.     tempRect.bottom = kMaxHeight;                    
  856.     growResult = GrowWindow(window, event->where, &tempRect);
  857.     if ( growResult != 0 ) {
  858.         EraseRect(&window->portRect);
  859.         SizeWindow(window, LoWord(growResult), HiWord(growResult), true);
  860.         SetRect(&gRect, kBord, kBord, LoWord(growResult)-kBord, HiWord(growResult)-kBottom);
  861.         MoveControl(gCPUctlH , gRect.left, gRect.bottom + 8);
  862.         MoveControl(gMCPctlH , gRect.left, gRect.bottom + 24);
  863.         InitNewRun(&gOffScreen);
  864.     }
  865.     SetPort(savePort);
  866.  
  867.  
  868. #pragma segment Main
  869. //===============================
  870. short NextLine(Ptr st, char **linePtr)
  871. //===============================
  872. {
  873.     short n;
  874.     
  875.     n = 0;
  876.     while ((n<gMBvars.ny) && ((state)st[n] != empty))
  877.         n++;
  878.     if (n<gMBvars.ny) {
  879.         (state)st[n] = busy;
  880.         *linePtr = (char *)gOffScreen.baseAddr + (n * gOffScreen.rowBytes);
  881.     }
  882.     return n;
  883. }
  884.  
  885.  
  886. #pragma segment Main
  887. //===============================
  888. void InitNewRun()
  889. //===============================
  890. {
  891.     short i;
  892.     Ptr p;
  893.     GrafPtr    savePort;
  894.     
  895.  
  896.     if (gTID > 0) 
  897.         ResetSlotServers();
  898.     
  899.     for (i=0; i<=kMaxHeight; gLineState[i++]=empty)
  900.         ;
  901.     gOffScreen.bounds = gRect;
  902.     i = (gOffScreen.rowBytes)*(gOffScreen.bounds.bottom - gOffScreen.bounds.top);
  903.     p = gOffScreen.baseAddr;
  904.     while (i-- >0)
  905.         *p++ = 0;
  906.         
  907.     gMBvars.ix = 0;
  908.     gMBvars.iy = -1;
  909.     gMBvars.yMCP = -1;
  910.     gMBvars.cntCPU = 0;
  911.     gMBvars.cntMCP = 0;
  912.     gMBvars.nx = gRect.right-gRect.left;
  913.     gMBvars.ny = gRect.bottom-gRect.top;
  914.     gMBvars.centerx = gMBvars.ncenterx;
  915.     gMBvars.centery = gMBvars.ncentery;
  916.     gMBvars.xextent = gMBvars.nxextent;
  917.     if (gMBvars.xextent > 0.5)
  918.         gMBvars.nmax = 50;
  919.     else if (gMBvars.xextent > 0.05)
  920.         gMBvars.nmax = 80;
  921.     else if (gMBvars.xextent > 0.005)
  922.         gMBvars.nmax = 120;
  923.     else
  924.         gMBvars.nmax = 200;
  925.     gMBvars.d  = rint(kDenom * gMBvars.xextent / gMBvars.nx + 0.5);
  926.     gMBvars.xa = rint(kDenom * (gMBvars.centerx - 0.5*gMBvars.xextent) + 0.5);
  927.     gMBvars.ya = rint(kDenom * gMBvars.centery + 0.5) - gMBvars.ny * gMBvars.d / 2;
  928.  
  929.     gDone = false;
  930.  
  931.     GetPort(&savePort);
  932.     SetPort(gMyWindow);
  933.     InvalRect(&gMyWindow->portRect);
  934.     SetPort(savePort);
  935.  
  936. }  // InitNewRun
  937.  
  938.  
  939. #pragma segment Main
  940. //===============================
  941. void ResetSlotServers()
  942. //===============================
  943. // this routine badly needs a re-design ... there are some major flaws in it
  944. {
  945.     short slot;
  946.     mMessage *m;
  947.  
  948.     for (slot=0; slot<16; slot++) {
  949.         if (gMCPpending[slot]) {
  950.              m = Receive(OS_MATCH_ALL, gServerTID[slot], OS_MATCH_ALL, (long)GetTickPS(), nil);
  951.             // look for message coming from gServerTID[slot], timeout 1 second
  952.             if ((long) m > 0) {
  953.                 if (m->mStatus != 0)    {        // message was undeliverable
  954.                     AlertUser(eUndeliverable);
  955.                     gServerTID[slot] = 0;     // no server any more in this slot!
  956.                 }
  957.                 FreeMsg(m);                    // dispose of this message anyway
  958.             }
  959.             gMCPpending[slot] = false;
  960.         }    // if gMCPpending
  961.         
  962.     }    // for each slot
  963.     
  964.     // is there still an active MBTask around ? 
  965.     // gServerTID[slot] could have been set to 0 if undeliverable messages were received
  966.     slot = 0;
  967.     while ((slot<16) && (gServerTID[slot] == 0))
  968.         slot++;
  969.     if (slot==16) {     // no use of A/ROSE any more
  970.         CloseQueue();
  971.         gMCP = false;
  972.         SetCtlValue(gMCPctlH, (short)gMCP);
  973.         gTID = 0;        // MCP checkbox will be disabled on next redraw
  974.     }
  975. } // ResetSlotServers()
  976.  
  977.  
  978. #pragma segment Initialize
  979. //===============================
  980. Boolean MakeOffScreen()
  981. //===============================
  982. {
  983. long offRowBytes;
  984.  
  985.     offRowBytes = ((kMaxWidth + 15) >> 4 ) << 1;
  986.     
  987.     gOffScreen.baseAddr = NewPtrClear(offRowBytes*kMaxHeight);
  988.     gOffScreen.rowBytes = offRowBytes;
  989.     gOffScreen.bounds = gRect;
  990.     return (gOffScreen.baseAddr != nil);
  991. }
  992.  
  993.  
  994.  
  995. #pragma segment Initialize
  996. //===============================
  997. short AROSEPrep(tid_type *t)
  998. //===============================
  999. {
  1000.     StringHandle sh;
  1001.     Str255 clientName = "?", clientType = "?",
  1002.              taskName     = "?", taskType     = "?";  // wasting lots of RAM, eh ?
  1003.  
  1004.     
  1005.     sh = GetString(rClientName);
  1006.     if (sh != nil)
  1007.         StringCopy(*sh,clientName);
  1008.     sh = GetString(rClientType);
  1009.     if (sh != nil)
  1010.         StringCopy(*sh,clientType);
  1011.     
  1012.     *t = OpenQueue(nil);
  1013.     if (t == 0) {                            // A/ROSE Prep out of order
  1014.         return(eNoAROSE);
  1015.     }
  1016.     if (!Register_Task (p2cstr(&clientName), p2cstr(&clientType), Machine_Visible)) 
  1017.         AlertUser(eRegister);
  1018.  
  1019.     sh = GetString(rTaskName);
  1020.     if (sh != nil)
  1021.         StringCopy(*sh,taskName);
  1022.     sh = GetString(rTaskType);
  1023.     if (sh != nil)
  1024.         StringCopy(*sh,taskType);
  1025.     if (FindAllServers(p2cstr(&taskName), p2cstr(&taskType)) > 0)
  1026.         return(noErr);
  1027.     else return(eNoServer);
  1028. }
  1029.  
  1030.  
  1031. #pragma segment Initialize
  1032. //===============================
  1033. short FindAllServers(char *name, char *type)
  1034. //===============================
  1035. // compare this with "ShowTasks.c" ! 
  1036. {
  1037.     short        slot;
  1038.      tid_type    tid,        // (result of Lookup_Task call)
  1039.                 sTID;        // the Name Manager TID for a given slot
  1040.     tid_type nCards[16]; // ICCM will fill in the Name Manager TID's
  1041.     unsigned short    index, agentsThere;
  1042.  
  1043.     
  1044.     if (! AskICCM((char *)nCards)) {
  1045.         AlertUser(eICCMproblem);
  1046.         return 0;
  1047.     }
  1048.     
  1049.     slot = 0;
  1050.     tid = 0;
  1051.     agentsThere = 0;
  1052.     do {
  1053.         index = 0;
  1054.         gServerTID[slot] = 0L;
  1055.         if (sTID = nCards[slot])
  1056.             gServerTID[slot] = Lookup_Task(name, type, sTID, &index);
  1057.         if (gServerTID[slot])
  1058.             agentsThere += 1;
  1059.     } while (slot++ < 16);
  1060.     return agentsThere;
  1061. }
  1062.  
  1063.  
  1064. #pragma segment Initialize
  1065. //===============================
  1066. Boolean     AskICCM(char *Cards)
  1067. //===============================
  1068. {
  1069.     Boolean result;
  1070.     mMessage    *m;
  1071.  
  1072.     if (GetICCTID() == 0) 
  1073.         return(false);
  1074.     
  1075.     if ((m = GetMsg()) == 0)
  1076.         return(false);
  1077.         
  1078.     m->mTo     = GetICCTID ();
  1079.     m->mCode     = ICC_GETCARDS;
  1080.     m->mDataPtr  = Cards;
  1081.     m->mDataSize = sizeof(tid_type) * 16;
  1082.     Send(m);
  1083.     m = Receive(OS_MATCH_ALL, OS_MATCH_ALL, ICC_GETCARDS+1, OS_NO_TIMEOUT, nil);
  1084.     // look for message with mCode = ICC_GETCARDS+1
  1085.     result = (m->mStatus == 0);  // slotInfo is in Cards[0..15] !
  1086.     FreeMsg(m);
  1087.     return(result);
  1088.         
  1089. } //     AskICCM()
  1090.  
  1091.  
  1092. #pragma segment Main
  1093. //===============================
  1094. void GetnewSelection()
  1095. //===============================
  1096. {
  1097. Point ratio, startPt, anewPt, newPt;
  1098. Rect tempRect;
  1099. short ncx, ncy;
  1100.  
  1101. #define abs(x)  ((x) >= 0) ? (x) : -(x)
  1102.  
  1103.     ratio.h = gMBvars.nx; ratio.v = gMBvars.ny;
  1104.     PenMode(patXor);
  1105.     PenPat(qd.gray);
  1106.     GetMouse(&startPt);
  1107.     SetRect(&tempRect, startPt.h, startPt.v, startPt.h, startPt.v);
  1108.     while (Button()) {
  1109.         FrameRect(&tempRect);
  1110.         GetMouse(&newPt);
  1111.         SubPt(startPt, &newPt);
  1112.         anewPt.h = abs(newPt.h);
  1113.         anewPt.v = abs(newPt.v);
  1114.     
  1115.         if (anewPt.h*ratio.v < anewPt.v*ratio.h)
  1116.             newPt.h = newPt.v * ratio.h / ratio.v;
  1117.         else
  1118.             newPt.v = newPt.h * ratio.v / ratio.h;
  1119.         SetRect(&tempRect,
  1120.             startPt.h, startPt.v, startPt.h+newPt.h, startPt.v+newPt.v);
  1121.         FrameRect(&tempRect);
  1122.     }
  1123.     PenNormal();
  1124.     ncx = (gRect.left + gRect.right - tempRect.left - tempRect.right)/2;
  1125.     ncy = (gRect.top + gRect.bottom - tempRect.top - tempRect.bottom)/2;
  1126.     gMBvars.ncenterx = gMBvars.centerx - gMBvars.xextent*ncx/gMBvars.nx;
  1127.     gMBvars.ncentery = gMBvars.centery - gMBvars.xextent*ncy/gMBvars.nx;
  1128.     gMBvars.nxextent = gMBvars.xextent*(tempRect.right - tempRect.left)/gMBvars.nx;
  1129. }
  1130.  
  1131.  
  1132. #pragma segment Initialize
  1133. //===============================
  1134. void StringCopy(char *s, char *t)
  1135. //===============================
  1136. {
  1137.     short n= (*t++ = *s++);
  1138.     while (n-- >0)
  1139.         *t++ = *s++;
  1140. }
  1141.